package com.xzzz.irda.guardcat.server.app.pojo;

import cn.hutool.core.util.StrUtil;
import com.xzzz.common.base.enums.FrameworkEnum;
import com.xzzz.irda.guardcat.core.constants.GuardcatConstant;
import com.xzzz.irda.guardcat.core.constants.MachineStatus;
import lombok.Data;

import java.util.List;
import java.util.Objects;

/**
 * 机器信息
 *
 * @author xzzz
 */
@Data
public class MachineInfo implements Comparable<MachineInfo> {

    /**
     * 机器ID
     */
    private String machineId;
    /**
     * 机器名称
     */
    private String hostName;
    /**
     * IP
     */
    private String ip;
    /**
     * 远程IP
     */
    private String remoteIp;
    /**
     * 端口
     */
    private Integer port;
    /**
     * 配置文件中的 context_path，前面会包含 "/"
     */
    private String servletContextPath;
    /**
     * 进程名称
     */
    private String processName;
    /**
     * 进程ID
     */
    private Integer processId;
    /**
     * 机器启动时间(JVM)
     */
    private String startTime;
    /**
     * 机器上线时间(JVM)
     */
    private Long uptime;
    /**
     * 机器运行时间(JVM)
     */
    private String runTime;
    /**
     * 应用名称
     *
     * @mock backend-bsms
     */
    private String appName;
    /**
     * 应用类型,当前的动态节点全部为SpringBoot
     *
     * @mock SpringBoot
     */
    private String appType;
    /**
     * 应用版本
     */
    private String appVersion;
    /**
     * 应用的环境配置
     *
     * @mock dev
     */
    private String profilesActive;
    /**
     * 应用使用的框架枚举集合
     */
    private List<FrameworkEnum> frameworks;
    /**
     * 应用最后心跳
     */
    private Long lastHeartbeatTime;
    /**
     * 应用状态, 只包含：ONLINE/OFFLINE
     *
     * @mock ONLINE
     */
    private String machineStatus;

    public MachineStatus getMachineStatus() {
        if (isOnline()) {
            return MachineStatus.ONLINE;
        }
        return MachineStatus.OFFLINE;
    }

    /**
     * 判断是否健康
     *
     * @return true:在线; false:不在线;
     */
    public boolean isOnline() {
        if (lastHeartbeatTime == null) {
            return false;
        }
        long delta = System.currentTimeMillis() - lastHeartbeatTime;
        return delta < GuardcatConstant.MACHINE_OFFLINE_THRESHOLD;
    }

    /**
     * @return true:死亡; false:未死亡;
     */
    public boolean isDead() {
        if (lastHeartbeatTime == null) {
            return true;
        }
        long delta = System.currentTimeMillis() - lastHeartbeatTime;
        return delta > GuardcatConstant.MACHINE_DEAD_THRESHOLD;
    }

    /**
     * 是否生产环境机器
     *
     * @return true:是; false:否;
     */
    public boolean isNotProd() {
        if (StrUtil.isBlank(this.profilesActive)) {
            return true;
        }
        if (GuardcatConstant.ENV_LOCAL.equals(this.profilesActive.toUpperCase())) {
            return false;
        }
        if (GuardcatConstant.ENV_PROD.equals(this.profilesActive.toUpperCase())) {
            return false;
        }
        return true;
    }

    public int getSort() {
        if (isDead()) {
            return 99;
        }
        if (GuardcatConstant.ENV_PROD.equals(this.profilesActive.toUpperCase())) {
            return 1;
        }
        if (GuardcatConstant.ENV_DEV.equals(this.profilesActive.toUpperCase())) {
            return 4;
        }
        return 5;
    }

    /**
     * 应用名称, IP, 端口相同, 则认为是同一台
     *
     * @param o
     * @return
     */
    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof MachineInfo)) {
            return false;
        }
        MachineInfo that = (MachineInfo) o;

        return
                Objects.equals(appName, that.appName) &&
                        Objects.equals(ip, that.ip) &&
                        Objects.equals(port, that.port)
                ;
    }

    @Override
    public int compareTo(MachineInfo o) {
        if (this == o) {
            return 0;
        }
        if (!port.equals(o.getPort())) {
            return port.compareTo(o.getPort());
        }
        if (!StrUtil.equals(appName, o.getAppName())) {
            return appName.compareToIgnoreCase(o.getAppName());
        }
        return ip.compareToIgnoreCase(o.getIp());
    }

    @Override
    public int hashCode() {
        return Objects.hash(appName, ip, port);
    }

    public String toLogString() {
        return String.format("%s|%s:%s", appName, ip, port);
    }
}
